home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 42 / Amiga Format AFCD42 (Issue 126, Aug 1999).iso / -serious- / comms / other / slrn / slrn_src / src / grplens.c < prev    next >
C/C++ Source or Header  |  1999-05-14  |  24KB  |  1,253 lines

  1. /* -*- mode: C; mode: fold -*- */
  2. /* Copyright (c) 1998 John E. Davis (davis@space.mit.edu)
  3.  *
  4.  * This file is part of slrn.
  5.  *
  6.  * Slrn is free software; you can redistribute it and/or modify it
  7.  * under the terms of the GNU General Public License as published by the
  8.  * Free Software Foundation; either version 2, or (at your option) any
  9.  * later version.
  10.  * 
  11.  * Slrn is distributed in the hope that it will be useful, but WITHOUT
  12.  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13.  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14.  * for more details.
  15.  * 
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with Slrn; see the file COPYING.  If not, write to the Free
  18.  * Software Foundation, 59 Temple Place - Suite 330, 
  19.  * Boston, MA  02111-1307, USA.
  20.  */
  21.  
  22.  
  23. #include "config.h"
  24. #include "slrnfeat.h"
  25.  
  26. #include <stdio.h>
  27. #include <string.h>
  28.  
  29. #if SLRN_HAS_GROUPLENS
  30. /* Rest of file in this #if statement */
  31.  
  32. #include <slang.h>
  33. #include <stdarg.h>
  34. #ifdef HAVE_STDLIB_H
  35. # include <stdlib.h>
  36. #endif
  37. #include <ctype.h>
  38.  
  39. #include "jdmacros.h"
  40.  
  41. #include "slrn.h"
  42. #include "group.h"
  43. #include "art.h"
  44. #include "misc.h"
  45. #include "uudecode.h"
  46. #include "grplens.h"
  47. #include "sltcp.h"
  48. #include "util.h"
  49. #include "server.h"
  50.  
  51.  
  52.  
  53. #define GL_MAX_RESPONSE_LINE_LEN    1024
  54.  
  55. /*{{{ GL_Type structure */
  56.  
  57. typedef struct GL_Type /*{{{*/
  58. {
  59.    char *hostname;
  60.    int port;
  61.    
  62.    char *token;
  63.    char *pseudoname;
  64.    int logged_in;
  65.    SLTCP_Type *tcp;
  66.    struct GL_Type *next;
  67. }
  68.  
  69. /*}}}*/
  70.  
  71. GL_Type;
  72.  
  73. static GL_Type GL_Nameserver;
  74. static GL_Type *GL_Server_List;
  75. /*}}}*/
  76.  
  77. typedef struct /*{{{*/
  78. {
  79.    char *msgid;
  80.    float pred;
  81.    float confhigh;
  82.    float conflow;
  83. }
  84.  
  85. /*}}}*/
  86. GL_Prediction_Type;
  87.  
  88. typedef struct /*{{{*/
  89. {
  90.    char *msgid;
  91.    int rating;
  92.    int saw_article;
  93. }
  94.  
  95. /*}}}*/
  96. GL_Rating_Type;
  97.  
  98. char *Slrn_GroupLens_Host;
  99. int Slrn_GroupLens_Port;
  100. char *Slrn_GroupLens_Pseudoname;
  101.  
  102. typedef struct GL_Newsgroup_List_Type /*{{{*/
  103. {
  104.    char *group;
  105.    GL_Type *gl;
  106.    struct GL_Newsgroup_List_Type *next;
  107. }
  108.  
  109. /*}}}*/
  110. GL_Newsgroup_List_Type;
  111.  
  112. static GL_Newsgroup_List_Type *Newsgroup_List = NULL;
  113.  
  114. /*{{{ Error codes and Error functions */
  115.  
  116. static int GL_Error;
  117. #define GL_ERROR_UNKNOWN           -1
  118. #define GL_ELOGIN_UNREGISTERED        1
  119. #define GL_ELOGIN_BUSY            2
  120. #define GL_ELOGIN_UNAVAILABLE        3
  121. #define GL_ELOGIN_ALREADY_LOGGEDIN    4
  122. #define GL_ERROR_PROPER_RESPONSE    6
  123. #define GL_ERROR_MALLOC            7
  124. #define GL_ESERVER_WRITE        8
  125. #define GL_ESERVER_READ            9
  126. #define GL_ERROR_TOKEN               10
  127. #define GL_ERROR_NEWSGROUP           11
  128.  
  129. typedef struct /*{{{*/
  130. {
  131.    char *err;
  132.    unsigned int len;
  133.    int errcode;
  134. }
  135.  
  136. /*}}}*/
  137.  
  138. GL_Error_Type;
  139.  
  140.  
  141.  
  142. /*{{{ Utility functions */
  143.  
  144. static char *make_nstring (char *s, unsigned int len) /*{{{*/
  145. {
  146.    char *s1;
  147.    
  148.    if (s == NULL) return s;
  149.    
  150.    if (NULL == (s1 = (char *) malloc (len + 1)))
  151.      {
  152.     GL_Error = GL_ERROR_MALLOC;
  153.     return NULL;
  154.      }
  155.    strncpy (s1, s, len);
  156.    s1[len] = 0;
  157.    return s1;
  158. }
  159.  
  160. /*}}}*/
  161.  
  162. static char *make_string (char *s) /*{{{*/
  163. {
  164.    if (s == NULL) return s;
  165.    return make_nstring (s, strlen (s));
  166. }
  167.  
  168. /*}}}*/
  169.  
  170. static char *skip_whitespace (char *s) /*{{{*/
  171. {
  172.    char ch;
  173.    
  174.    while (((ch = *s) != 0) && isspace(ch)) s++;
  175.    return s;
  176. }
  177.  
  178. /*}}}*/
  179.  
  180. static char *skip_nonwhitespace (char *s) /*{{{*/
  181. {
  182.    char ch;
  183.    
  184.    while (((ch = *s) != 0) && (0 == isspace(ch))) s++;
  185.    return s;
  186. }
  187.  
  188. /*}}}*/
  189.  
  190. /*}}}*/
  191.  
  192. static char *gl_get_error (void) /*{{{*/
  193. {
  194.    switch (GL_Error)
  195.      {
  196.       case GL_ELOGIN_UNREGISTERED: return "User is Unregistered";
  197.       case GL_ELOGIN_BUSY: return "Service is Busy";
  198.       case GL_ELOGIN_UNAVAILABLE: return "Service Unavailable";
  199.       case GL_ELOGIN_ALREADY_LOGGEDIN: return "Already logged in";
  200.       case GL_ERROR_PROPER_RESPONSE: return "Server failed to return proper response";
  201.       case GL_ERROR_MALLOC: return "Not enough memory";
  202.       case GL_ESERVER_WRITE: return "Error writing to server";
  203.       case GL_ESERVER_READ: return "Error reading from server";
  204.       case GL_ERROR_TOKEN: return "Token is invalid";
  205.       case GL_ERROR_NEWSGROUP: return "Newsgroup not supported";
  206.      }
  207.    
  208.    return "Unknown Error";
  209. }
  210.  
  211. /*}}}*/
  212.  
  213.  
  214. static void close_gl (GL_Type *gl) /*{{{*/
  215. {
  216.    if (gl == NULL) return;
  217.    sltcp_close (gl->tcp);
  218.    gl->tcp = NULL;
  219. }
  220.  
  221. /*}}}*/
  222.  
  223. static int get_gl_response (GL_Type *gl, char *buf, unsigned int len) /*{{{*/
  224. {
  225.    char *b;
  226.    
  227.    (void) len;
  228.    
  229.    if (-1 == sltcp_fgets (gl->tcp, buf, GL_MAX_RESPONSE_LINE_LEN))
  230.      {
  231.     GL_Error = GL_ESERVER_READ;
  232.     close_gl (gl);
  233.     return -1;
  234.      }
  235.    
  236.    b = buf + strlen (buf);
  237.    if (b != buf)
  238.      {
  239.     b--;
  240.     if (*b == '\n') *b = 0;
  241.     if (b != buf)
  242.       {
  243.          b--;
  244.          if (*b == '\r') *b = 0;
  245.       }
  246.      }
  247.    return 0;
  248. }
  249.  
  250. /*}}}*/
  251.  
  252. static void handle_error_response (GL_Type *gl, GL_Error_Type *tbl) /*{{{*/
  253. {
  254.    char *s, *s1;
  255.    char buf [GL_MAX_RESPONSE_LINE_LEN];
  256.    
  257.    if (-1 == get_gl_response (gl, buf, sizeof (buf)))
  258.      return;
  259.    
  260.    if (tbl == NULL)
  261.      return;
  262.  
  263.    s = skip_whitespace (buf);
  264.    
  265.    GL_Error = GL_ERROR_UNKNOWN;
  266.    
  267.    while (*s != 0)
  268.      {
  269.     unsigned int len;
  270.     GL_Error_Type *t;
  271.     
  272.     s1 = skip_nonwhitespace (s);
  273.     
  274.     len = s1 - s;
  275.     
  276.     t = tbl;
  277.     while (t->err != NULL)
  278.       {
  279.          if ((t->len == len) 
  280.          && (0 == slrn_case_strncmp ((unsigned char *)s, (unsigned char *) t->err, len)))
  281.            {
  282.           GL_Error = t->errcode;
  283.           if (GL_Error == GL_ERROR_TOKEN)
  284.             {
  285.                if (gl->token != NULL)
  286.              free (gl->token);
  287.                gl->token = NULL;
  288.                gl->logged_in = 0;
  289.             }
  290.           break;
  291.            }
  292.          t++;
  293.       }
  294.     s = skip_whitespace (s1);
  295.      }
  296.    
  297.    close_gl (gl);
  298. }
  299.  
  300. /*}}}*/
  301.  
  302.    
  303. static int is_error (char *buf) /*{{{*/
  304. {
  305.    if (!slrn_case_strncmp ((unsigned char *) buf, (unsigned char *) "ERROR", 5))
  306.      return 1;
  307.    
  308.    return 0;
  309. }
  310.  
  311. /*}}}*/
  312.  
  313. /*}}}*/
  314.  
  315. /*{{{ parse_keyword_eqs_value */
  316.  
  317. /* Scan buf looking for keyword=VALUE */
  318. static int parse_keyword_eqs_value (char *buf, char *kw, char **value, unsigned int *len) /*{{{*/
  319. {
  320.    char *b, *b1, *v, *v1;
  321.    char ch;
  322.    unsigned int kwlen;
  323.  
  324.    *value = NULL;
  325.  
  326.    kwlen = strlen (kw);
  327.    
  328.    b = buf;
  329.    while (1)
  330.      {
  331.     b = skip_whitespace (b);
  332.     if (*b == 0) return -1;
  333.     
  334.     b1 = b;
  335.     while (((ch = *b1) != 0) && (0 == isspace (ch)) && (ch != '='))
  336.       b1++;
  337.     
  338.     if (ch == 0) return -1;
  339.     if (ch != '=')
  340.       {
  341.          b = b1;
  342.          continue;
  343.       }
  344.     
  345.     v = b1 + 1;
  346.     if (*v == '"')
  347.       {
  348.          v++;
  349.          v1 = v;
  350.          while (((ch = *v1) != 0) && (ch != '"')) v1++;
  351.       }
  352.     else v1 = skip_nonwhitespace (v);
  353.     
  354.     if ((b + kwlen == b1) 
  355.         && (0 == slrn_case_strncmp ((unsigned char *) kw, (unsigned char *) b, kwlen)))
  356.       {
  357.          *value = v;
  358.          *len = v1 - v;
  359.          return 0;
  360.       }
  361.     
  362.     if (*v1 == '"') v1++;
  363.     b = v1;
  364.      }
  365. }
  366.  
  367. /*}}}*/
  368.  
  369. /*}}}*/
  370. /*{{{ low level GL server functions */
  371.  
  372.    
  373. static int send_gl_line (GL_Type *gl, char *msg, int flush) /*{{{*/
  374. {
  375.    if (msg == NULL) return 0;
  376.    
  377.    if ((-1 == sltcp_fputs (gl->tcp, msg))
  378.        || (-1 == sltcp_fputs (gl->tcp, "\r\n"))
  379.        || (flush && (-1 == sltcp_flush_output (gl->tcp))))
  380.      {
  381.     GL_Error = GL_ESERVER_WRITE;
  382.     close_gl (gl);
  383.     return -1;
  384.      }
  385.    
  386.    return 0;
  387. }
  388.  
  389. /*}}}*/
  390.  
  391. static int connect_to_gl_host (GL_Type *gl, char *cmd) /*{{{*/
  392. {
  393.    char buf [GL_MAX_RESPONSE_LINE_LEN];
  394.    char *host;
  395.    int port;
  396.  
  397.    GL_Error = 0;
  398.    
  399.    port = gl->port;
  400.    if (NULL == (host = gl->hostname))
  401.      {
  402.     host = Slrn_GroupLens_Host;
  403.     port = Slrn_GroupLens_Port;
  404.      }
  405.    
  406.    if ((host == NULL) || (port <= 0))
  407.      {
  408.     GL_Error = GL_ERROR_UNKNOWN;
  409.     return -1;
  410.      }
  411.    
  412.    if (NULL == (gl->tcp = sltcp_open_connection (host, port)))
  413.      return -1;
  414.    
  415.    /* We should be able to read OK ...  If not, we failed to make proper 
  416.     * connection.
  417.     */
  418.  
  419.    if (-1 == get_gl_response (gl, buf, sizeof (buf)))
  420.      return -1;
  421.    
  422.    if (0 != slrn_case_strncmp ((unsigned char *) buf, (unsigned char *) "OK", 2))
  423.      {
  424.     GL_Error = GL_ERROR_PROPER_RESPONSE;
  425.     close_gl (gl);
  426.     return -1;
  427.      }
  428.    
  429.    return send_gl_line (gl, cmd, 1);
  430. }
  431.  
  432. /*}}}*/
  433.  
  434.  
  435. static int start_command (GL_Type *gl, char *fmt, ...) /*{{{*/
  436. {
  437.    va_list ap;
  438.    int ret;
  439.    
  440.    if (-1 == connect_to_gl_host (gl, NULL))
  441.      return -1;
  442.    
  443.    va_start(ap, fmt);
  444.    ret = sltcp_vfprintf (gl->tcp, f